
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ElasticSearch学习文档 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>ElasticSearch学习文档 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">什么是 `CompletableFuture`？它主要解决了 Java 中 `Future` 接口的哪些局限性？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`CompletableFuture` 是 Java 8 引入的 `Future` 接口的增强实现，专为异步编程设计。它解决了 `Future` 的几个核心局限性：1) `Future` 无法被手动完成；2) 不支持非阻塞式的回调函数，只能通过 `get()` 方法阻塞等待结果；3) 不支持多个 `Future` 组合操作；4) 没有统一的异常处理机制。</div>
          </div>
          <div class="card-source">来源: 1. 什么是 CompletableFuture？</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">创建 `CompletableFuture` 实例时，`runAsync()` 和 `supplyAsync()` 方法有什么核心区别？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">核心区别在于任务是否有返回值。`runAsync()` 方法接收一个 `Runnable` 对象，用于执行没有返回值的异步任务，因此它返回 `CompletableFuture<Void>`。而 `supplyAsync()` 方法接收一个 `Supplier<T>` 对象，用于执行有返回值的异步任务，并返回一个 `CompletableFuture<T>`，其中 `T` 是返回值的类型。</div>
          </div>
          <div class="card-source">来源: 2. 创建 CompletableFuture</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请解释 `thenApply()`, `thenAccept()` 和 `thenRun()` 这三个回调方法在处理上一个阶段结果时的不同之处。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">这三个方法都用于在前一个 `CompletableFuture` 完成后执行操作，但处理结果的方式不同：<br>1. `thenApply(Function)`: 接收一个函数，它会处理上一个阶段的结果，并返回一个带有新结果的 `CompletableFuture`。<br>2. `thenAccept(Consumer)`: 接收一个消费者，它会处理上一个阶段的结果，但没有返回值，因此返回 `CompletableFuture<Void>`。<br>3. `thenRun(Runnable)`: 接收一个 `Runnable`，它不关心上一个阶段的结果，只在任务完成后执行指定操作，同样返回 `CompletableFuture<Void>`。</div>
          </div>
          <div class="card-source">来源: 3.1. thenApply(), 3.2. thenAccept() 和 thenRun()</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">当需要链接一个本身返回 `CompletableFuture` 的异步操作时，为什么推荐使用 `thenCompose()` 而不是 `thenApply()`？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">因为如果使用 `thenApply()` 来链接一个返回 `CompletableFuture` 的函数，结果会是一个嵌套的 `CompletableFuture<CompletableFuture<T>>`，这会使后续的操作变得复杂。而 `thenCompose()` 方法专门用于处理这种情况，它会自动将两层 `CompletableFuture` “压平”（flatten），直接返回一个 `CompletableFuture<T>`，使得链式调用更加简洁和直观。</div>
          </div>
          <div class="card-source">来源: 3.3. thenCompose()</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">`thenCombine()` 方法的作用是什么？它与 `thenCompose()` 的核心应用场景有何不同？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`thenCombine()` 用于将两个**独立**的 `CompletableFuture` 的结果合并。当这两个 Future 都完成时，它会将它们的结果作为参数传递给一个 `BiFunction` 并返回一个新的 `CompletableFuture`。而 `thenCompose()` 用于链接两个**有依赖关系**的 `CompletableFuture`，即第二个 Future 的执行依赖于第一个 Future 的结果。</div>
          </div>
          <div class="card-source">来源: 3.4. thenCombine()</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">`CompletableFuture.allOf()` 和 `CompletableFuture.anyOf()` 的用途和返回结果有何区别？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`allOf()` 和 `anyOf()` 都用于处理多个 `CompletableFuture`。<br>- `allOf()`: 当所有给定的 `CompletableFuture` 都完成时，返回的 `CompletableFuture<Void>` 才会完成。它不返回任何组合结果，主要用于等待一组任务全部结束。<br>- `anyOf()`: 当任何一个给定的 `CompletableFuture` 完成时，返回的 `CompletableFuture<Object>` 就会完成，并且其结果是第一个完成的 Future 的结果。</div>
          </div>
          <div class="card-source">来源: 3.5. allOf() 和 anyOf()</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在 `CompletableFuture` 的异常处理中，`exceptionally()` 方法扮演什么角色？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`exceptionally()` 方法提供了一种类似于 `try-catch` 中 `catch` 块的恢复机制。它接收一个函数，如果异步计算链中的任何一个前置阶段抛出异常，该函数就会被执行。这个函数可以根据捕获到的异常返回一个默认值或替代值，从而让后续的计算能够正常继续下去，避免整个流程因异常而中断。</div>
          </div>
          <div class="card-source">来源: 4.1. exceptionally()</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">`handle()` 方法与 `exceptionally()` 方法在处理异步任务结果时的主要区别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主要区别在于 `handle()` 总是会被执行，无论前一个阶段是正常完成还是抛出异常。它的回调函数接收两个参数：结果（result）和异常（exception），这两个参数中只有一个会是非 `null` 的。这使得 `handle()` 可以在一个地方同时处理成功和失败两种情况，类似于 `try-catch-finally` 中的 `finally` 块，并且它还能转换结果。</div>
          </div>
          <div class="card-source">来源: 4.2. handle()</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">`whenComplete()` 方法的主要用途是什么？它是否会改变 `CompletableFuture` 链的结果？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`whenComplete()` 方法的主要用途是在 `CompletableFuture` 完成时（无论是正常完成还是异常完成）执行一个附加操作，通常用于实现日志记录、监控或清理等副作用（side-effects）。它不会改变计算链的结果；它接收结果和异常作为参数，但其本身返回 `CompletableFuture<Void>`，并将原始的结果或异常原封不动地传递给下游。</div>
          </div>
          <div class="card-source">来源: 4.3. whenComplete()</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
